#ifndef CLASSE_H
#define CLASSE_H 1

#include "ADDObjetBase.h"

#include <iostream>
#include <vector>
#include <map>
#include <set>

#include "TypeClasse.h"
#include "Sort.h"
#include "Prerequis.h"
//#include "ListComp.h"
//#include "ListEnsComp.h"
#include "CompetenceClasse.h"
#include "EnsembleCompetencesClasse.h"

using namespace std;

/**
 * La classe Classe représente une classe au sens AD&D. C'est une
 * classe abstraite, qui sert au polymorphisme. Ici se fait la gestion
 * des diverses restrictions et compétences, qui sont lues depuis
 * chaque type de classe. L'objet Classe contient tous les attributs
 * et accesseurs communs aux différents types de classes.
 *
 * On ne stocke ici que des pointeurs sur les listes (et nombre) de
 * compétences et restrictions.
 *
 * Les codes d'erreurs valides sont compris entre 300 et 399.\n
 * - 320 : tentative d'accéder à un ensemble racial inexistant
 *   (dépassement d'indice).
 * - 350 : la race choisie n'a pas accès la la classe voulue.
 *
 * @author Johan "Solo" Luisier
 */
class Classe : public ADDObjetBase
{
 private:
  /**
   * Permet de déterminer si les niveaux de sorties ont bien été
   * initialisés.
   */
  static bool niveauxLus;
  /**
   * Liste des noms des niveaux de sorties paramétrables.
   */
  static const vector< string > NomsNiveaux;
  /**
   * Est utilisé comme valeur de renvoi pour une compétence, un trait
   * ou le nombre de compétences lorsque le conteneur n'est pas
   * défini.
   */
  static const unsigned PasTrouve;
 protected:
  /*
   * Niveau, niveau magique et nombre de pts d'expérience.
   */
  unsigned
    Niveau, /**< Niveau dans cette classe, calculé automatiquement. */
    NiveauMagique, /**< Niveau de magie dans cette classe, calculé
		      automatiquement. */
    PV, /**< Nombre de pt de vie pour cette classe. */
    XP; /**< Nombre de pt d'expérience dans cette classe. */
  /* /\** */
  /*  * Valeurs des traits du personnage, le 7ème contient le score de */
  /*  * force exceptionnel (0 si non applicable). */
  /*  *\/ */
  /* vector< unsigned > Traits; */
  /**
   * Nom de la classe ("Rôdeur", "Barde", ...).
   */
  string NomClasse;
  /*
   * Nom de la Race, utilisé lors de la détermination des scores et
   * des traits.
   */
  //string NomRace;
  /**
   * Liste des compétences que l'objet courant possède. Il s'agit de
   * la liste des \b numéros des compétences dans la liste de
   * l'instance. Si une compétences est associée à un pourcentage, ce
   * pourcentage est également stocké ici.
   */
  vector<unsigned> Competences;
  /**
   * Liste des sorts du livre de sort (Mages, Spécialistes et Bardes
   * uniquement).
   */
  vector<Sort> SortsClasse;
  /**
   * Type de classe (TypeClasse) disponibles, détermine les
   * compétences non-martiales accessibles. Est déterminé d'après la
   * classe dérivée lors de la création de l'objet.
   *
   * @see TypeClasse
   */
  vector<TypeClasse> TC;
  /**
   * Niveau de sortie des fonctions globales, très simples. On peut
   * changer cette constante en modifiant la ligne Classe::elementaire
   * du fichier CONFIG.
   */
  static DebugLevelType elementaire;
  /**
   * Niveau de sortie des fonctions plus spécifiques de Classe. La
   * valeur de cette constante est définie par la ligne
   * Classe::fonction du fichier CONFIG.
   */
  static DebugLevelType fonction;
  /**
   * Nombre de points de personnages (PP) disponible pour la création
   * de la Classe.
   */
  unsigned NombrePPsAlloues;
  /**
   * Nombre de compétences existantes.
   */
  unsigned NombreTotalCompetences;
  /**
   * Nombre de restrictions existantes.
   */
  unsigned NombreTotalRestrictions;
  /**
   * Nombre d'ensembles de compétences existants.
   */
  unsigned NombreTotalEnsembles;
  /**
   * Nombre maximal de compétences dans un ensemble de compétences.
   */
  unsigned NombreMaxCompetences;
  /**
   * Contient les compétences de classe dans la première "ligne". Si
   * la Classe possède des compétences "à tiroirs", ces compétences
   * sont dans les "lignes" suivantes.
   */
  vector< vector< CompetenceClasse > > ListesCompetences;
  /**
   * Contient les restrictions de classe.
   */
  vector< CompetenceClasse > ListeRestrictions;
  /**
   * Liste des ensembles de compétences.
   */
  vector< EnsembleCompetencesClasse > EnsemblesCompetences;
  /**
   * Liste des préreqis sur les traits pour la classe. Lorsqu'il
   * existe plusieurs ensembles avec des prérequis variables, ils sont
   * alors écrits sur plusieurs "lignes".
   */
  vector< vector< Prerequis > > PrerequisClasse;
  /**
   * Liste des Races admises pour la Classe. Lorsqu'il existe
   * plusieurs ensembles avec des prérequis variables, ils sont alors
   * écrits sur plusieurs "lignes".
   */
  vector< set< string > > RacesAdmisesClasse;
  /**
   * Calcule le niveau du personnage, en fonction de sa classe et de son
   * nombre de pts d'expérience.
   */
  virtual void calculNiveau() = 0;
  /**
   * Calcule le TAC0 du personnage
   */
  virtual unsigned calculeTAc0() const = 0;
  /**
   * Calcule le niveau de magie du personnage, en fonction de sa classe
   * et de son niveau (recalculé par précaution). Si le personnage n'a pas
   * de sorts ou a un niveau insuffisant pour en lancer, le niveau magique
   * calculé est 0.
   */
  virtual void calculNivMag() = 0;
 public:
  /*
   * Construction et destruction de l'objet.
   */
  Classe();
  Classe( const unsigned& xp, const TypeClasse& tc, const string& nomClasse );
  Classe( const Classe& classe );
  virtual ~Classe();
  void construitClasse( unsigned& pps, const vector< unsigned >& traits,
                        const string& nomRace );

  /*
   * Accesseurs
   */
  unsigned tailleCompetences() const;
  const unsigned& numCompetence( const unsigned& i ) const;
  const unsigned& pv() const;
  const unsigned& xp() const;
  const unsigned& pp() const;
  const unsigned& niveau() const;
  const unsigned& niveauMagie() const;
  const string& classe() const;
  const string& nomCompetence( const unsigned& i,
                               const bool& LaTeX = false ) const;
  string nomCompetence( const unsigned& i, const string& nomRace,
                        const vector< unsigned >& traits,
                        bool& sauter, const bool& LaTeX = false ) const;
  virtual bool forceExceptionnelle( const unsigned& force ) const;
  const vector<TypeClasse>* tc() const;

  /* const vector< unsigned >* traits() const; */
  /* const unsigned& trait(const unsigned& i) const; */

  const vector<unsigned>* competences( unsigned& nbr ) const;

  void copieCompetencesClasse( unsigned& nbrComp,
                               vector<CompetenceClasse>& comp,
                               unsigned& nbrRes,
                               vector<CompetenceClasse>& restric ) const;
  const vector< CompetenceClasse >* listesCompetences( const unsigned& num = 0 ) const;

  const CompetenceClasse& competenceNumero( const unsigned& i ) const;
  bool possedePourcent() const;

  virtual const unsigned& valeurBase( const unsigned& i ) const;
  virtual string scoreAdditionnel( const unsigned& i,
                                   const string& nomRace,
                                   const vector< unsigned >& traits ) const;
  virtual unsigned pourcent( const bool& lvlUp ) const;

  virtual void donneesEnsCompetences( unsigned& nbr, unsigned& max ) const;
  const vector< EnsembleCompetencesClasse >* ensembles() const;
  const unsigned* nbrEns() const;
  const unsigned* maxEns() const;

  virtual void sortsParNiveau( vector< unsigned >& sorts,
			       const unsigned& sagesse ) const;
  unsigned nbrSortsConnus() const;
  const Sort& sortNum( const unsigned& i ) const;
  const vector<Sort>* adresseSorts() const;

  /**
   * Fait correspondre le prix d'accès à une compétence martiale en
   * fonction de la classe du personnage.
   *
   * @param[out] Map pointeur sur la map qui sera la table de
   * correspondance.
   */
  virtual void prixAcces( map<string, unsigned>*& Map ) const = 0;
  /**
   * Permet de savoir si l'instance de classe peut avoir une ou
   * plusieurs spécialisations martiales.
   *
   * @retval 0 si non, @retval 1 si une spécialisation possible,
   * @retval 2 si spécialisations multiples.
   */
  virtual unsigned aSpecialisation() const = 0;
  /**
   * Calcule les JS du personnage et les met dans le tableau passé en
   * argument. Si le personnage a plusieurs classes, les JS les plus
   * avantageux seront automatiquement sélectionnés dans la classe
   * Joueur.
   *
   * @param[out] tab pointeur sur le tableau contenant les JS.
   */
  virtual void js( unsigned *tab ) const = 0;

  /*
   * Modificateurs
   */
  static void setLevel( const unsigned& level, const unsigned& n );
  void setCompetences( const vector<unsigned>& capa );
  /* void setTraits(const vector< unsigned >& traits); */
  /* void setTrait(const unsigned& i, const unsigned& val); */
  void setPV( const unsigned& pv );
  void setXP( const unsigned& xp );
  virtual void ajoutSorts();
  void ajoutSorts( const vector<Sort>& vec );
  void setSorts( const vector<Sort>& sorts );
  void augmenterXP( const unsigned& xp );
  void augmenterPV( const unsigned& pv );
  virtual void augmenterTalents( const string& nomRace,
				 const vector< unsigned >& traits,
				 const bool& lvl_up = true );

  /*
   * Affichage
   */
  void affiche( ostream& os ) const;
  void afficheStats( const string& nomRace,
                     const vector< unsigned >& traits,
                     ostream& os ) const;
  void afficheCompetences( const string& nomRace,
                           const vector< unsigned >& traits,
                           ostream& os ) const;
  void affiche( FlotMessage& flot ) const;
  void afficheStats( const string& nomRace,
                     const vector< unsigned >& traits,
                     FlotMessage& flot ) const;
  void afficheCompetences( const string& nomRace,
                           const vector< unsigned >& traits,
                           FlotMessage& flot ) const;

  unsigned calculeNombres();
  virtual void ecrireSorts( const string& nom_fichier, const bool& ecrase,
                            const unsigned& sagesse = -1u ) const;
  string supprimeAccents( const string& brut ) const;

  virtual StatusCode prerequisOK( const string& race,
                                  const vector< unsigned >& traits,
                                  const unsigned& ensemble = 0 );
  virtual void appliquerModif( const string& nomRace,
                               const unsigned& dexterite );
};

#endif
